package io.itit.ecp.admin.provide.action.controller;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.CarbonQuotaInputTypeEnums;
import io.itit.ecp.admin.common.enums.IMeterDeviceEnums;
import io.itit.ecp.admin.provide.action.req.CarbonCCERQueryReq;
import io.itit.ecp.admin.provide.action.resp.CarbonCCERResp;
import io.itit.ecp.admin.provide.action.resp.CarbonCCERStaticsResp;
import io.itit.ecp.admin.provide.helper.SceneHelper;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.service.ICarbonCCERService;
import io.itit.ecp.admin.server.service.ICarbonPriceDataService;
import io.itit.grass.common.provide.action.req.BaseBatchIdReq;
import io.itit.grass.common.provide.action.req.BaseIdReq;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.IAdd;
import io.itit.grass.common.provide.action.validation.IQueryPage;
import io.itit.grass.common.provide.action.validation.IRequired;
import io.itit.grass.common.provide.action.validation.IUpdate;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * ccer管理
 */
@Api(tags = "ccer管理")
@RestController
@RequestMapping("/ecp-admin/carbonccer")
public class CarbonCCERController {

    @Resource
    private ICarbonCCERService carbonCCERService;

    @Resource
    private ICarbonPriceDataService carbonPriceDataService;

    @ApiOperation("分页查询")
    @PostMapping("queryPage")
    @RequiresPermissions("ecp-admin:carbonccer:search")
    public ResultResp<IPage<CarbonCCERResp>> queryPage(@RequestBody @Validated(IQueryPage.class) CarbonCCERQueryReq req) {
        Page<CarbonCCERResp> page = buildQW(req).joinPage(PageUtils.getPage(req, CarbonCCERResp.class), CarbonCCERResp.class);
//        for (CarbonCCERResp item : page.getRecords()) {
//            Date createTm = item.getCreateTm();
//            if (!StringUtils.pathEquals(item.getInputType(), CarbonQuotaInputTypeEnums.ADD.getValue())) {
//                List<CarbonPriceDataEntity> list = carbonPriceDataService.list(new LambdaQueryWrapper<CarbonPriceDataEntity>()
//                        .eq(CarbonPriceDataEntity::getSceneProjectId, item.getSceneProjectId())
//                        .ge(CarbonPriceDataEntity::getDataTime, DateUtil.beginOfDay(createTm))
//                        .le(CarbonPriceDataEntity::getDataTime, DateUtil.endOfDay(createTm))
//                        .orderByDesc(CarbonPriceDataEntity::getDataTime)
//                );
//                if (!list.isEmpty()) {
//                    item.setCarbonIncome(list.get(0).getCcerPrice().multiply(item.getCcerValue()));
//                    if (StringUtils.pathEquals(item.getInputType(), CarbonQuotaInputTypeEnums.PURCHASE.getValue())) { //购入为负数
//                        item.setCarbonIncome(item.getCarbonIncome().negate());
//                    }
//                }
//            }
//        }
        return ResultResp.success(SceneHelper.i().setSceneInfo(page));
    }

    @ApiOperation("统计")
    @PostMapping("statics")
    @RequiresPermissions("ecp-admin:carbonccer:search")
    public ResultResp<CarbonCCERStaticsResp> statics(@RequestBody CarbonCCERQueryReq req) {
        LocalDateTime startTime = StringUtils.hasLength(req.getStartTime()) ? LocalDate.parse(req.getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay() : null;
        LocalDateTime endTime = StringUtils.hasLength(req.getEndTime()) ? LocalDate.parse(req.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        CarbonCCERStaticsResp staticsResp = new CarbonCCERStaticsResp();
        List<CarbonCCEREntity> carbonCCEREntities = carbonCCERService.list(new LambdaQueryWrapper<CarbonCCEREntity>()
                .eq(StringUtils.hasLength(req.getSceneProjectId()), CarbonCCEREntity::getSceneProjectId, req.getSceneProjectId())
                .eq(StringUtils.hasLength(req.getSceneEdificeId()), CarbonCCEREntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(StringUtils.hasLength(req.getSceneFloorId()), CarbonCCEREntity::getSceneFloorId, req.getSceneFloorId())
                .eq(StringUtils.hasLength(req.getSceneRoomId()), CarbonCCEREntity::getSceneRoomId, req.getSceneRoomId())
                .ge(Objects.nonNull(startTime), CarbonCCEREntity::getCreateTm, startTime)
                .le(CarbonCCEREntity::getCreateTm, endTime)
        );
        Map<String, List<CarbonCCEREntity>> inputTypeMap = carbonCCEREntities.stream().collect(Collectors.groupingBy(CarbonCCEREntity::getInputType));
        staticsResp.setSaleValue(inputTypeMap.getOrDefault(CarbonQuotaInputTypeEnums.SOLD.getValue(), Collections.emptyList())
                .stream().map(CarbonCCEREntity::getCcerValue).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN));
        staticsResp.setPurchasedValue(inputTypeMap.getOrDefault(CarbonQuotaInputTypeEnums.PURCHASE.getValue(), Collections.emptyList())
                .stream().map(CarbonCCEREntity::getCcerValue).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN));

        staticsResp.setTotalValue(queryReductionData(req.getSceneProjectId(), req.getSceneEdificeId(), req.getSceneEdificeId(), req.getSceneRoomId(), req.getStartTime(), req
                .getEndTime()).add(staticsResp.getPurchasedValue()).setScale(2, RoundingMode.HALF_DOWN));

        staticsResp.setRemainingValue(staticsResp.getTotalValue()
                .subtract(staticsResp.getSaleValue()));
        BigDecimal income = BigDecimal.ZERO;
        for (CarbonCCEREntity item : carbonCCEREntities) {
            if (Objects.isNull(item.getCarbonIncome())) {
                income = income.add(carbonCCERService.calculateCarbonIncome(item.getSceneProjectId(), item.getInputType(), item.getCcerValue(), item.getCreateTm()));
            } else {
                income = income.add(item.getCarbonIncome());
            }
        }
        staticsResp.setCarbonIncome(income);

        return ResultResp.success(staticsResp);
    }

    private BigDecimal queryReductionData(String sceneProjectId,
                                          String sceneEdificeId,
                                          String sceneFloorId,
                                          String sceneRoomId,
                                          String startTime, String endTime) {
        BigDecimal data = Joins.of(EnergyDataEntity.class)
                .selectAs(consumer -> consumer
                        .add("SUM(carbon_emission)", "carbonEmission", false)
                )
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneRoomId, sceneRoomId)
                .ge(StringUtils.hasLength(startTime), EnergyDataEntity::getSolidifyDate, startTime)
                .le(StringUtils.hasLength(endTime), EnergyDataEntity::getSolidifyDate, endTime)
                .joinGetOne(BigDecimal.class);
        return ObjectUtil.defaultIfNull(data, BigDecimal.ZERO);
    }

    @ApiOperation("新增")
    @PostMapping("add")
    @RequiresPermissions("ecp-admin:carbonccer:add")
    public ResultResp<Boolean> add(@RequestBody @Validated({IAdd.class}) CarbonCCEREntity req) {
        if (Objects.isNull(req.getCreateTm())) {
            req.setCreateTm(new Date());
        }
        req.setCarbonIncome(carbonCCERService.calculateCarbonIncome(req.getSceneProjectId(), req.getInputType(), req.getCcerValue(), req.getCreateTm()));
        boolean res = carbonCCERService.save(req);
        return ResultResp.success(res);
    }

    @ApiOperation("编辑")
    @PostMapping("update")
    @RequiresPermissions("ecp-admin:carbonccer:update")
    public ResultResp<Boolean> update(@RequestBody @Validated({IUpdate.class}) CarbonCCEREntity req) {
        CarbonCCEREntity carbonCCEREntity = carbonCCERService.getById(req.getId());
        if (Objects.isNull(carbonCCEREntity)) {
            return ResultResp.fail("更新数据不存在");
        }
        req.setCarbonIncome(carbonCCERService.calculateCarbonIncome(req.getSceneProjectId(), req.getInputType(), req.getCcerValue(), carbonCCEREntity.getCreateTm()));

        boolean res = carbonCCERService.updateById(req);
        return ResultResp.success(res);
    }

    @ApiOperation("删除(根据Id删)")
    @PostMapping("deleteById")
    @RequiresPermissions("ecp-admin:carbonccer:deleteById")
    public ResultResp<Boolean> deleteById(@RequestBody @Validated({IRequired.class}) BaseIdReq req) {
        return ResultResp.success(carbonCCERService.removeById(req.getId()));
    }

    @ApiOperation("批量删除")
    @PostMapping("batchDelete")
    @RequiresPermissions("ecp-admin:carbonccer:batchDelete")
    public ResultResp<Boolean> batchDelete(@RequestBody @Validated({IRequired.class}) BaseBatchIdReq req) {
        return ResultResp.success(carbonCCERService.removeBatchByIds(req.getIds(), 1000));
    }

    private static JoinLambdaWrapper<CarbonCCEREntity> buildQW(CarbonCCERQueryReq req) {
        return Joins.of(CarbonCCEREntity.class)
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, CarbonCCEREntity::getSceneProjectId)
                .selectAs(SceneProjectEntity::getProjectName, CarbonCCERResp::getProjectName)
                .end()
                .eq(StringUtils.hasLength(req.getSceneProjectId()), CarbonCCEREntity::getSceneProjectId, req.getSceneProjectId())
                .eq(StringUtils.hasLength(req.getSceneEdificeId()), CarbonCCEREntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(StringUtils.hasLength(req.getSceneFloorId()), CarbonCCEREntity::getSceneFloorId, req.getSceneFloorId())
                .eq(StringUtils.hasLength(req.getSceneRoomId()), CarbonCCEREntity::getSceneRoomId, req.getSceneRoomId())
                .ge(StringUtils.hasLength(req.getStartTime()), CarbonCCEREntity::getCreateTm, req.getStartTime())
                .le(StringUtils.hasLength(req.getEndTime()), CarbonCCEREntity::getCreateTm, req.getEndTime())
                .orderByDesc(CarbonCCEREntity::getCreateTm);
    }

}
